﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Web;
using Domaine;
using Ninject;
using Persistance.ViewModel;
using Repository;

namespace Persistance
{
    public class GestionProjet : IGestionProjet
    {
        [Inject]
        public IUnitOfWork UnitOfWork { get; set; }

        private bool IsInfDateYMD(DateTime a, DateTime b)
        {
            return (a.Year < b.Year || (a.Year == b.Year && a.Month < b.Month) || (a.Year == b.Year && a.Month == b.Month && a.Day <= b.Day));
        }

        private Expression<Func<DateTime, DateTime, bool>> isInfDateYMD = (a, b) => (a.Year < b.Year || (a.Year == b.Year && a.Month < b.Month) || (a.Year == b.Year && a.Month == b.Month && a.Day <= b.Day));

        /// <summary>
        /// Récupère les projets de l'année sur lesquels le collab travaillera
        /// </summary>
        /// <param name="login"></param>
        /// <param name="year"></param>
        /// <returns></returns>
        public CalendarYear GetCalendarYear(string login, int year)
        {
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);
            var tasks = collab.TaskSet.Where(t => t.BeginDate.Year <= year && t.EndDate.Year >= year).ToList();

            var reponse = new CalendarYear { CalendarYearProjectSet = new List<CalendarYearProjects>() };

            for (var i = 0; i < 12; i++)
            {
                reponse.CalendarYearProjectSet.Add(new CalendarYearProjects { ProjectSet = new List<ProjectCalendarModel>() });
                var tasksInMonth = tasks.Where(t => (t.BeginDate.Year < year || (t.BeginDate.Year == year && t.BeginDate.Month <= i + 1)) && (t.EndDate.Year > year || (t.EndDate.Year == year && t.EndDate.Month >= i + 1))).ToList();
                for (int j = 0; j < tasksInMonth.Count; j++)
                {
                    if (reponse.CalendarYearProjectSet[i].ProjectSet.Any(p => p.Reference == tasksInMonth.ElementAt(j).Project.Reference))
                        continue;

                    var modelCalendarYear = new ProjectCalendarModel
                    {
                        ColorCode = tasksInMonth.ElementAt(j).Project.ColorCode,
                        Name = tasksInMonth.ElementAt(j).Project.Name,
                        Reference = tasksInMonth.ElementAt(j).Project.Reference
                    };
                    reponse.CalendarYearProjectSet.ElementAt(i).ProjectSet.Add(modelCalendarYear);
                }
            }

            return reponse;
        }

        /// <summary>
        /// Récupère les projets du mois de l'année sur lesquels le collab travaillera
        /// </summary>
        /// <param name="login"></param>
        /// <param name="year"></param>
        /// <param name="month"></param>
        /// <returns></returns>
        public CalendarMonth GetCalendarMonth(string login, int year, int month)
        {
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);
            var tasks = collab.TaskSet.Where(t => (t.BeginDate.Year < year || (t.BeginDate.Year == year && t.BeginDate.Month <= month)) && (t.EndDate.Year > year || (t.EndDate.Year == year && t.EndDate.Month >= month))).ToList();

            var reponse = new CalendarMonth { CalendarMonthProjectSet = new List<CalendarMonthProjects>() };

            for (var i = 0; i < DateTime.DaysInMonth(year, month); i++)
            {
                var date = new DateTime(year, month, i + 1);
                reponse.CalendarMonthProjectSet.Add(new CalendarMonthProjects { ProjectSet = new List<ProjectCalendarModel>() });
                var taskOfDay = tasks.Where(t => IsInfDateYMD(t.BeginDate, date) && IsInfDateYMD(date, t.EndDate)).ToList();
                for (var j = 0; j < taskOfDay.Count; j++)
                {
                    if (reponse.CalendarMonthProjectSet[i].ProjectSet.Any(p => p.Reference == taskOfDay.ElementAt(j).Project.Reference))
                        continue;

                    reponse.CalendarMonthProjectSet[i].ProjectSet.Add(
                        new ProjectCalendarModel
                        {
                            ColorCode = taskOfDay.ElementAt(j).Project.ColorCode,
                            Name = taskOfDay.ElementAt(j).Project.Name,
                            Reference = taskOfDay.ElementAt(j).Project.Reference
                        });
                }
            }

            return reponse;
        }

        /// <summary>
        /// Récupère les projets de la semaine sur lesquels le collab travaillera
        /// </summary>
        /// <param name="login"></param>
        /// <param name="year"></param>
        /// <param name="month"></param>
        /// <param name="firstDay"></param>
        /// <param name="lastDay"></param>
        /// <returns></returns>
        public CalendarWeek GetCalendarWeek(string login, int fyear, int fmonth, int fday, int lyear, int lmonth, int lday)
        {
            var dateDeb = new DateTime(fyear, fmonth, fday);
            var dateFin = new DateTime(lyear, lmonth, lday);
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);
            var tasks = collab.TaskSet.Where(t => (IsInfDateYMD(dateDeb, t.EndDate) && IsInfDateYMD(t.EndDate, dateFin)) ||
                                                    (IsInfDateYMD(dateDeb, t.BeginDate) && IsInfDateYMD(t.BeginDate, dateFin)) ||
                                                    (IsInfDateYMD(t.BeginDate, dateDeb) && IsInfDateYMD(dateFin, t.EndDate))
                                            ).ToList();

            var reponse = new CalendarWeek { ProjectSet = new List<ProjectDetailModel>() };

            for (var i = 0; i < tasks.Count; i++)
            {
                var tmpProjet = tasks[i].Project;
                var projectAndCollab = new ProjectDetailModel { };
                projectAndCollab.Name = tmpProjet.Name;
                projectAndCollab.Reference = tmpProjet.Reference;
                projectAndCollab.ColorCode = tmpProjet.ColorCode;
                projectAndCollab.WeekColabList = new List<List<CollaborateurModel>>{new List<CollaborateurModel>(), 
                        new List<CollaborateurModel>(),
                        new List<CollaborateurModel>(),
                        new List<CollaborateurModel>(),
                        new List<CollaborateurModel>()};

                for (var j = 0; j < 5; j++)
                {
                    var tmpDate = dateDeb.AddDays(j);
                    var taskOfDay = tasks.Where(t => t.Project.Reference.Equals(tmpProjet.Reference) && IsInfDateYMD(t.BeginDate, tmpDate) && IsInfDateYMD(tmpDate, t.EndDate)).ToList();

                    foreach (Task otherTasks in taskOfDay)
                    {
                        var collabModel = new CollaborateurModel
                        {
                            Name = otherTasks.Collaborator.Name,
                            FirstName = otherTasks.Collaborator.FirstName,
                            ImageInfo = new ImageInfoViewModel
                            { 
                                URLImage = otherTasks.Collaborator.URLImage, 
                                LastModification=otherTasks.Collaborator.ModificationDate 
                            }
                        };
                        projectAndCollab.WeekColabList[j].Add(collabModel);
                    }
                }
                reponse.ProjectSet.Add(projectAndCollab);
            }
            return reponse;
        }

        /// <summary>
        /// Récupère le calendrier du projet en vue par année
        /// </summary>
        /// <param name="login"></param>
        /// <param name="year"></param>
        /// <param name="reference"></param>
        /// <returns></returns>
        public CalendarYear GetProjectCalendarYear(string login, int year, string reference)
        {
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            //verification de la reference en paramètre
            if (!UnitOfWork.ProjectRepository.Exists(p => p.Reference == reference))
            {
                throw new Exception("Le projet ayant la référence " + reference + " n'existe pas.");
            }

            Project project = UnitOfWork.ProjectRepository.Single(p => p.Reference == reference);

            //taches du collaborateur relative au projet pour l'année parametree
            var tasks = collab.TaskSet.Where(t =>
                t.BeginDate.Year <= year && t.EndDate.Year >= year
                && t.Project.Reference == reference).ToList();

            var reponse = new CalendarYear { CalendarYearProjectSet = new List<CalendarYearProjects>() };

            for (var i = 0; i < 12; i++)
            {
                reponse.CalendarYearProjectSet.Add(new CalendarYearProjects { ProjectSet = new List<ProjectCalendarModel>() });
                //taches du collaborateur relative au projet pour chaque mois de l'année
                var tasksInMonth = tasks.Where(t =>
                    (t.BeginDate.Year < year || (t.BeginDate.Year == year && t.BeginDate.Month <= i + 1))
                    && (t.EndDate.Year > year || (t.EndDate.Year == year && t.EndDate.Month >= i + 1))).ToList();

                for (int j = 0; j < tasksInMonth.Count; j++)
                {
                    if (reponse.CalendarYearProjectSet[i].ProjectSet.Any(p =>
                        p.Reference == tasksInMonth.ElementAt(j).Project.Reference))
                        continue;

                    var modelCalendarYear = new ProjectCalendarModel
                    {
                        ColorCode = project.ColorCode,
                        Name = project.Name,
                        Reference = project.Reference
                    };
                    reponse.CalendarYearProjectSet.ElementAt(i).ProjectSet.Add(modelCalendarYear);
                }
            }

            return reponse;
        }

        /// <summary>
        /// Récupère le calendrier du projet en vue du mois de l'année parametrées
        /// </summary>
        /// <param name="login"></param>
        /// <param name="year"></param>
        /// <param name="month"></param>
        /// <param name="reference"></param>
        /// <returns></returns>
        public CalendarMonth GetProjectCalendarMonth(string login, int year, int month, string reference)
        {
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            //verification de la reference en paramètre
            if (!UnitOfWork.ProjectRepository.Exists(p => p.Reference == reference))
            {
                throw new Exception("Le projet ayant la référence " + reference + " n'existe pas.");
            }
            Project project = UnitOfWork.ProjectRepository.Single(p => p.Reference == reference);

            //taches du collaborateur relative au projet pour le mois et l'année parametrees
            var tasks = collab.TaskSet.Where(t =>
                (t.BeginDate.Year < year || (t.BeginDate.Year == year && t.BeginDate.Month <= month))
                && (t.EndDate.Year > year || (t.EndDate.Year == year && t.EndDate.Month >= month))
                && t.Project.Reference == reference).ToList();

            var reponse = new CalendarMonth { CalendarMonthProjectSet = new List<CalendarMonthProjects>() };

            for (var i = 0; i < DateTime.DaysInMonth(year, month); i++)
            {
                var date = new DateTime(year, month, i + 1);
                reponse.CalendarMonthProjectSet.Add(new CalendarMonthProjects { ProjectSet = new List<ProjectCalendarModel>() });
                //taches du collaborateur relative au projet pour chaque jour du mois et de l'année parametrees
                var taskOfDay = tasks.Where(t => IsInfDateYMD(t.BeginDate, date) && IsInfDateYMD(date, t.EndDate)).ToList();
                for (var j = 0; j < taskOfDay.Count; j++)
                {
                    if (reponse.CalendarMonthProjectSet[i].ProjectSet.Any(p => p.Reference == taskOfDay.ElementAt(j).Project.Reference))
                        continue;

                    reponse.CalendarMonthProjectSet[i].ProjectSet.Add(
                        new ProjectCalendarModel
                        {
                            ColorCode = project.ColorCode,
                            Name = project.Name,
                            Reference = reference
                        });
                }
            }

            return reponse;
        }

        /// <summary>
        /// Récupère le calendrier du projet en vue de la semaine parametrée
        /// </summary>
        /// <param name="login"></param>
        /// <param name="fyear"></param>
        /// <param name="fmonth"></param>
        /// <param name="fday"></param>
        /// <param name="lyear"></param>
        /// <param name="lmonth"></param>
        /// <param name="lday"></param>
        /// <param name="reference"></param>
        /// <returns></returns>
        public CalendarWeek GetProjectCalendarWeek(string login, int fyear, int fmonth, int fday, int lyear, int lmonth, int lday, string reference)
        {

            //verification de la reference en paramètre
            if (!UnitOfWork.ProjectRepository.Exists(p => p.Reference == reference))
            {
                throw new Exception("Le projet ayant la référence " + reference + " n'existe pas.");
            }
            Project project = UnitOfWork.ProjectRepository.Single(p => p.Reference == reference);

            var dateDeb = new DateTime(fyear, fmonth, fday);
            var dateFin = new DateTime(lyear, lmonth, lday);
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);
            //taches du collaborateur relative au projet pour la date parametree
            var tasks = collab.TaskSet.Where(t => t.Project.Reference == reference && ((IsInfDateYMD(dateDeb, t.EndDate) && IsInfDateYMD(t.EndDate, dateFin)) ||
                                                    (IsInfDateYMD(dateDeb, t.BeginDate) && IsInfDateYMD(t.BeginDate, dateFin)) ||
                                                    (IsInfDateYMD(t.BeginDate, dateDeb) && IsInfDateYMD(dateFin, t.EndDate)))
                                            ).ToList();

            var reponse = new CalendarWeek { ProjectSet = new List<ProjectDetailModel>() };

            for (var i = 0; i < tasks.Count; i++)
            {
                var projectAndCollab = new ProjectDetailModel { };
                projectAndCollab.Name = project.Name;
                projectAndCollab.Reference = project.Reference;
                projectAndCollab.ColorCode = project.ColorCode;
                projectAndCollab.WeekColabList = new List<List<CollaborateurModel>>{new List<CollaborateurModel>(), 
                        new List<CollaborateurModel>(),
                        new List<CollaborateurModel>(),
                        new List<CollaborateurModel>(),
                        new List<CollaborateurModel>()};

                for (var j = 0; j < 5; j++)
                {
                    var tmpDate = dateDeb.AddDays(j);
                    var taskOfDay = tasks.Where(t => t.Project.Reference == project.Reference && IsInfDateYMD(t.BeginDate, tmpDate) && IsInfDateYMD(tmpDate, t.EndDate)).ToList();

                    foreach (Task otherTasks in taskOfDay)
                    {
                        var collabModel = new CollaborateurModel
                        {
                            Name = otherTasks.Collaborator.Name,
                            FirstName = otherTasks.Collaborator.FirstName,
                            ImageInfo = new ImageInfoViewModel
                            {
                                URLImage = otherTasks.Collaborator.URLImage,
                                LastModification = otherTasks.Collaborator.ModificationDate
                            }
                        };
                        projectAndCollab.WeekColabList[j].Add(collabModel);
                    }
                }
                reponse.ProjectSet.Add(projectAndCollab);
            }
            return reponse;
        }
       
        /// <summary>
        /// Recupère tous les projet de l'année pour le collab
        /// </summary>
        /// <param name="login"></param>
        /// <param name="year"></param>
        /// <returns></returns>
        public List<ProjectFullDetailModel> GetAllProjectForYear(string login, int year)
        {
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            var reponse = new List<ProjectFullDetailModel>();

            foreach (Project projet in collab.ProjectSet)
            {
                if (year >= projet.BeginDate.Year && year <= projet.EndDate.Year)
                    reponse.Add(new ProjectFullDetailModel
                    {
                        Reference = projet.Reference,
                        Name = projet.Name,
                        State = projet.State.Name,
                        EndDate = projet.EndDate,
                        BeginDate = projet.BeginDate,
                        Client = projet.Client
                    });
            }

            return reponse;
        }

        /// <summary>
        /// Retourne les details du projet dont la reference est donnee en parametre
        /// </summary>
        /// <param name="reference"></param>
        /// <returns></returns>
        public ProjectFullDetailModel GetProject(string login, string reference)
        {
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            //verification de la reference en paramètre
            if (!UnitOfWork.ProjectRepository.Exists(p => p.Reference == reference))
            {
                throw new Exception("Le projet ayant la référence " + reference + " n'existe pas.");
            }
            //verification des droits du collaborateur
            if ((collab.Job.ID != (int)JobEnum.ChefProjet) && (collab.Job.ID != (int)JobEnum.RA))
            {
                throw new Exception("Vous n'avez pas les droits necessaires.");
            }

            var project = UnitOfWork.ProjectRepository.Single(p => p.Reference == reference);

            //verification collab associe au projet
            if (!collab.ProjectSet.Contains(project) || !project.CollaboratorSet.Contains(collab))
            {
                throw new Exception("Vous ne travaillez pas sur ce projet.");
            }

            var reponse = new ProjectFullDetailModel();

            reponse.Reference = project.Reference;
            reponse.Client = project.Client;
            reponse.Name = project.Name;
            reponse.State = project.State.Name;
            reponse.BeginDate = project.BeginDate;
            reponse.EndDate = project.EndDate;
            reponse.ColorCode = project.ColorCode;
            reponse.StateID = project.State.ID;

            return reponse;
        }

        /// <summary>
        /// Retourne les chefs de projet suivant le critère de recherche passé en paramètre
        /// </summary>
        /// <param name="leaderProjectLogin"></param>
        /// <returns></returns>
        public List<LeaderProjectSimpleModel> GetLeaderProject(string critere)
        {
            var reponse = new List<LeaderProjectSimpleModel>();
            //recupere les chef de projets actifs correspondant au critere
            var leaderProjects = UnitOfWork.CollaboratorRepository.Find(c => c.Job.ID == (int)JobEnum.ChefProjet && c.IsActive && (c.Login.Contains(critere) || c.Name.Contains(critere) || c.FirstName.Contains(critere))).ToList();

            foreach (Collaborator collab in leaderProjects)
                reponse.Add(new LeaderProjectSimpleModel
                {
                    LogIn = collab.Login,
                    FirstName = collab.FirstName,
                    Name = collab.Name,
                    ImageInfo = new ImageInfoViewModel
                    {
                        URLImage = collab.URLImage,
                        LastModification = collab.ModificationDate
                    }
                });


            return reponse;
        }

        /// <summary>
        /// Retourne les collaborateurs suivant le critère de recherche passé en paramètre
        /// </summary>
        /// <param name="critere"></param>
        /// <returns></returns>
        public List<CollaboratorViewModel> GetCollaborators(string critere)
        {
            var reponse = new List<CollaboratorViewModel>();
            //recupere les collaborateurs actifs correspondant au critere
            var collabs = UnitOfWork.CollaboratorRepository.Find(c => c.IsActive &&(c.Login.Contains(critere) || c.FirstName.Contains(critere) || c.Name.Contains(critere))).ToList();
            foreach (Collaborator collab in collabs)
            {
                reponse.Add(new CollaboratorViewModel
                {
                    FirstName = collab.FirstName,
                    Name = collab.Name,
                    ImageInfo = new ImageInfoViewModel
                    { 
                                URLImage = collab.URLImage, 
                                LastModification=collab.ModificationDate 
                    },
                    Login = collab.Login,
                    Email = collab.Email,
                    MobilePhone = collab.MobilePhone,
                    Location = collab.Location.Name,
                    Job = collab.Job.Name,
                    IsActive= collab.IsActive
                });
            }

            return reponse;
        }

        /// <summary>
        /// Ajoute un nouveau projet 
        /// </summary>
        /// <param name="login"></param>
        /// <param name="reference"></param>
        /// <param name="name"></param>
        /// <param name="state"></param>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <param name="client"></param>
        /// <param name="color"></param>
        public void AddProject(string login, string reference, string name, DateTime beginDate, DateTime endDate, string client, string color, string loginCP)
        {
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            //verification des droits de l'utilisateur
            if ((collab.Job.ID != (int)JobEnum.ChefProjet) && (collab.Job.ID != (int)JobEnum.RA))
            {
                throw new Exception("Vous n'avez pas les droits necessaires.");
            }
            //verification de la reference
            if (UnitOfWork.ProjectRepository.Exists(p => p.Reference == reference))
            {
                throw new Exception("Un projet ayant la référence " + reference + " existe déjà.");
            }
            //verification des dates
            if (beginDate > endDate)
            {
                throw new Exception("La date de début doit être antérieur a la date de fin.");
            }
            //verification du loginCP
            if (!UnitOfWork.CollaboratorRepository.Exists(c => c.Login == loginCP && c.IsActive && c.Job.ID == (int)JobEnum.ChefProjet))
            {
                throw new Exception("Le chef de projet n'est pas valide.");
            }
            var collabCP = UnitOfWork.CollaboratorRepository.Single(c => c.Login == loginCP && c.Job.ID == (int)JobEnum.ChefProjet);

            //creation du nouveau projet
            Project project = new Project();
            project.Reference = reference;
            project.Name = name;
            project.BeginDate = beginDate;
            project.EndDate = endDate;
            project.ColorCode = color;
            project.CollaboratorSet.Add(collabCP);
            project.Client = client;
            project.State = UnitOfWork.StateRepository.Single(s => s.ID == (int)StateEnum.EnCours);

            //ajout
            UnitOfWork.ProjectRepository.Add(project);

            //ajout pour le CP
            collabCP.ProjectSet.Add(project);
            //ratachement du RA de l'activité du CP
            var activity = collabCP.Activity.ID;
            var collabRA = UnitOfWork.CollaboratorRepository.Single(c => c.Activity.ID == activity);
            project.CollaboratorSet.Add(collabRA);
            collabRA.ProjectSet.Add(project);

            //terminer
            UnitOfWork.Save();
        }

        /// <summary>
        /// Edition d'un projet
        /// </summary>
        /// <param name="login"></param>
        /// <param name="reference"></param>
        /// <param name="name"></param>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <param name="state"></param>
        /// <param name="client"></param>
        /// <param name="color"></param>
        public void EditProject(string login, string reference, string name, DateTime beginDate, DateTime endDate, int state, string client, string color)
        {
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            //verification des droits de l'utilisateur
            if (collab.Job.ID != (int)JobEnum.ChefProjet && collab.Job.ID != (int)JobEnum.RA)
            {
                throw new Exception("Vous n'avez pas les droits necessaires.");
            }
            //verification de la reference
            if (!UnitOfWork.ProjectRepository.Exists(p => p.Reference == reference))
            {
                throw new Exception("Le projet ayant la référence " + reference + " n'existe pas.");
            }
            //verification des dates
            if (beginDate > endDate)
            {
                throw new Exception("La date de début doit être antérieur a la date de fin.");
            }

            Project project = UnitOfWork.ProjectRepository.Single(p => p.Reference == reference);

            //verification collab associe au projet
            if (!collab.ProjectSet.Contains(project) || !project.CollaboratorSet.Contains(collab))
            {
                throw new Exception("Vous ne travaillez pas sur ce projet.");
            }

            project.Name = name;
            project.BeginDate = beginDate;
            project.EndDate = endDate;
            project.Client = client;
            project.ColorCode = color;
            project.State = UnitOfWork.StateRepository.Single(s => s.ID == state);

            //terminer
            UnitOfWork.Save();
        }

        /// <summary>
        /// Retourne la liste des collaborateur participant au projet referencé en paramètre
        /// </summary>
        /// <param name="login"></param>
        /// <param name="reference"></param>
        /// <returns></returns>
        public List<CollaboratorViewModel> GetTeamProject(string login, string reference)
        {
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            //verification de la reference en paramètre
            if (!UnitOfWork.ProjectRepository.Exists(p => p.Reference == reference))
            {
                throw new Exception("Le projet ayant la référence " + reference + " n'existe pas.");
            }
            //verification des droits du collaborateur
            if ((collab.Job.ID != (int)JobEnum.ChefProjet) && (collab.Job.ID != (int)JobEnum.RA))
            {
                throw new Exception("Vous n'avez pas les droits necessaires.");
            }

            var project = UnitOfWork.ProjectRepository.Single(p => p.Reference == reference);

            //verification collab associe au projet
            if (!collab.ProjectSet.Contains(project) || !project.CollaboratorSet.Contains(collab))
            {
                throw new Exception("Vous ne travaillez pas sur ce projet.");
            }

            var reponse = new List<CollaboratorViewModel>();
            foreach (Collaborator teamCollab in project.CollaboratorSet)
                reponse.Add(new CollaboratorViewModel
                {
                    Login = teamCollab.Login,
                    FirstName = teamCollab.FirstName,
                    Location = teamCollab.Location.Name,
                    Job = teamCollab.Job.Name,
                    Name = teamCollab.Name,
                    Email = teamCollab.Email,
                    MobilePhone = teamCollab.MobilePhone,
                    ImageInfo = new ImageInfoViewModel
                    {
                        URLImage = teamCollab.URLImage,
                        LastModification = teamCollab.ModificationDate
                    },
                    IsActive = collab.IsActive
                });

            return reponse;
        }

        /// <summary>
        /// Ajoute un collaborateur (loginCollab) a l'equipe travaillant sur le projet (reference)
        /// </summary>
        /// <param name="login"></param>
        /// <param name="reference"></param>
        /// <param name="loginCollab"></param>
        public void AddCollabToTeamProject(string login, string reference, string loginCollab)
        {
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            //verification des droits de l'utilisateur
            if (collab.Job.ID != (int)JobEnum.ChefProjet && collab.Job.ID != (int)JobEnum.RA)
            {
                throw new Exception("Vous n'avez pas les droits necessaires.");
            }

            //verification de la reference
            if (!UnitOfWork.ProjectRepository.Exists(p => p.Reference == reference))
            {
                throw new Exception("Le projet ayant la référence " + reference + " n'existe pas.");
            }
            Project project = UnitOfWork.ProjectRepository.Single(p => p.Reference == reference);

            //verification du loginCollab
            if (!UnitOfWork.CollaboratorRepository.Exists(c => c.Login == loginCollab && c.IsActive))
            {
                throw new Exception("Le collaborateur " + loginCollab + " n'existe pas.");
            }
            Collaborator collabToAdd = UnitOfWork.CollaboratorRepository.Single(c => c.Login == loginCollab);

            //verification collab associe au projet
            if (!collab.ProjectSet.Contains(project) || !project.CollaboratorSet.Contains(collab))
            {
                throw new Exception("Vous ne travaillez pas sur ce projet.");
            }

            //verification si le collaborateur à ajouter est déjà associé au projet
            if (project.CollaboratorSet.Contains(collabToAdd))
            {
                throw new Exception("Le collaborateur " + loginCollab + " est déjà associé au projet.");
            }

            //Association collaborateur / projet
            project.CollaboratorSet.Add(collabToAdd);
            collabToAdd.ProjectSet.Add(project);

            UnitOfWork.Save();

        }

        /// <summary>
        /// Enlève un collaborateur de l'equipe du projet
        /// </summary>
        /// <param name="login"></param>
        /// <param name="reference"></param>
        /// <param name="loginCollab"></param>
        public void RemoveCollabFromTeamProject(string login, string reference, string loginCollab)
        {
            var collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            //verification des droits de l'utilisateur
            if (collab.Job.ID != (int)JobEnum.ChefProjet && collab.Job.ID != (int)JobEnum.RA)
            {
                throw new Exception("Vous n'avez pas les droits necessaires.");
            }

            //verification de la reference
            if (!UnitOfWork.ProjectRepository.Exists(p => p.Reference == reference))
            {
                throw new Exception("Le projet ayant la référence " + reference + " n'existe pas.");
            }
            Project project = UnitOfWork.ProjectRepository.Single(p => p.Reference == reference);

            //verification du loginCollab
            if (!UnitOfWork.CollaboratorRepository.Exists(c => c.Login == loginCollab && c.IsActive))
            {
                throw new Exception("Le collaborateur " + loginCollab + " n'existe pas.");
            }
            Collaborator collabToRemove = UnitOfWork.CollaboratorRepository.Single(c => c.Login == loginCollab);

            //verification collabToRemove associe au projet
            if (!collabToRemove.ProjectSet.Contains(project) || !project.CollaboratorSet.Contains(collabToRemove))
            {
                throw new Exception("Le collaborateur " + loginCollab + "ne travaille pas sur ce projet.");
            }
            //verification que collabToRemove ne soit pas le dernier chef de projet
            if (project.CollaboratorSet.Count(c => c.Job.ID == (int)JobEnum.ChefProjet) < 2 && collabToRemove.Job.ID == (int)JobEnum.ChefProjet)
            {
                throw new Exception("Il doit y avoir au moins un chef de projet dans l'équipe");
            }

            //verification collab associe au projet
            if (!collab.ProjectSet.Contains(project) || !project.CollaboratorSet.Contains(collab))
            {
                throw new Exception("Vous ne travaillez pas sur ce projet.");
            }

            //Suppression de l'association collaborateur / projet
            project.CollaboratorSet.Remove(collabToRemove);
            collabToRemove.ProjectSet.Remove(project);

            UnitOfWork.Save();
        }

        /// <summary>
        /// Retourne tous les états possibles
        /// </summary>
        /// <returns></returns>
        public List<ViewModel.State> GetAllState()
        {
            return UnitOfWork.StateRepository.All().Select((state) => new ViewModel.State { ID = state.ID, Name = state.Name }).ToList();
        }

        /// <summary>
        /// Ajouter une liste de taches
        /// </summary>
        /// <param name="login"></param>
        /// <param name="tasks"></param>
        public void AddTasks( string login, List<TaskViewModel> tasks)
        {  
            Collaborator collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            foreach(TaskViewModel task in tasks )
            {
                //verification de la référence (ajout d'une tache sur un projet non clos)
                if (!UnitOfWork.ProjectRepository.Exists(p => p.Reference == task.ReferenceProject && p.State.ID!=(int) StateEnum.Termine))
                {
                    throw new Exception("Le projet ayant la référence " + task.ReferenceProject + " n'existe pas.");
                }
                Project project = UnitOfWork.ProjectRepository.Single(p => p.Reference == task.ReferenceProject);

                //verification du loginCollab
                if (!UnitOfWork.CollaboratorRepository.Exists(c => c.Login == task.LoginCollab && c.IsActive))
                {
                    throw new Exception("Le collaborateur " + task.LoginCollab + " n'existe pas.");
                }
                Collaborator collabTask = UnitOfWork.CollaboratorRepository.Single(c => c.Login == task.LoginCollab);
                
                //si ajout d'une tache pour un autre collaborateur => le collab loggué est un RA ou CP (associés)
                if (!(task.LoginCollab != login &&
                    (collab.Job.ID == (int)JobEnum.ChefProjet && Utils.CollabAssociateToCP(collab, collabTask)) ||
                    (collab.Job.ID == (int)JobEnum.RA && Utils.CollabAssociateToRA(collab, collabTask))
                ))
                {
                    throw new Exception("Vous n'avez pas les droits necessaires.");
                }
                //verification collabTask associe au projet
                if (!collabTask.ProjectSet.Contains(project) || !project.CollaboratorSet.Contains(collabTask))
                {
                    throw new Exception("Vous ne travaillez pas sur ce projet.");
                }
                //verification des dates
                if (project.BeginDate >= task.BeginDate && task.BeginDate > task.EndDate && task.EndDate >= project.EndDate)
                {
                    throw new Exception("La date de début doit être antérieur a la date de fin.");
                }
                
                AddTask(task,collabTask,project);

                UnitOfWork.Save();
            }
        }

        /// <summary>
        /// Ajouter une tache /!\ les verifications sont faites dans add Tasks
        /// </summary>
        /// <param name="task"></param>
        /// <param name="collab"></param>
        /// <param name="project"></param>
        private void AddTask(TaskViewModel task, Collaborator collab, Project project)
        {
            Task newTask = new Task();
            newTask.BeginDate =task.BeginDate;
            newTask.EndDate = task.EndDate;
            newTask.TaskType = UnitOfWork.TaskTypeRepository.Single(t => t.ID == task.TypeOfTask);
            newTask.TJM = task.TJM;
            newTask.Collaborator = collab;
            newTask.Project = project;

            UnitOfWork.Save();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="login"></param>
        /// <param name="idTask"></param>
        /// <param name="task"></param>
        public void EditTask(string login, int idTask, TaskViewModel task)
        {
            Collaborator collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            //verification de task
            if (! UnitOfWork.TaskRepository.Exists(t => t.ID == idTask))
            {
                throw new Exception("La tâche " + idTask + " n'existe pas");
            }

            //verification de la référence (ajout d'une tache sur un projet non clos)
            if (!UnitOfWork.ProjectRepository.Exists(p => p.Reference == task.ReferenceProject && p.State.ID != (int)StateEnum.Termine))
            {
                throw new Exception("Le projet ayant la référence " + task.ReferenceProject + " n'existe pas.");
            }
            Project project = UnitOfWork.ProjectRepository.Single(p => p.Reference == task.ReferenceProject);

            //verification du loginCollab
            if (!UnitOfWork.CollaboratorRepository.Exists(c => c.Login == task.LoginCollab && c.IsActive))
            {
                throw new Exception("Le collaborateur " + task.LoginCollab + " n'existe pas.");
            }
            Collaborator collabTask = UnitOfWork.CollaboratorRepository.Single(c => c.Login == task.LoginCollab);

            //si ajout d'une tache pour un autre collaborateur => le collab loggué est un RA ou CP (associés)
            if (!(task.LoginCollab != login &&
                (collab.Job.ID == (int)JobEnum.ChefProjet && Utils.CollabAssociateToCP(collab, collabTask)) ||
                (collab.Job.ID == (int)JobEnum.RA && Utils.CollabAssociateToRA(collab, collabTask))
            ))
            {
                throw new Exception("Vous n'avez pas les droits necessaires.");
            }
            //verification collabTask associe au projet
            if (!collabTask.ProjectSet.Contains(project) || !project.CollaboratorSet.Contains(collabTask))
            {
                throw new Exception("Vous ne travaillez pas sur ce projet.");
            }
            //verification des dates
            if (project.BeginDate >= task.BeginDate && task.BeginDate > task.EndDate && task.EndDate >= project.EndDate)
            {
                throw new Exception("La date de début doit être antérieur a la date de fin.");
            }

            Task taskToEdit = UnitOfWork.TaskRepository.Single(t => t.ID == idTask);
            taskToEdit.Project = project;
            taskToEdit.TaskType = UnitOfWork.TaskTypeRepository.Single(t => t.ID == task.TypeOfTask);
            taskToEdit.TJM = task.TJM;
            taskToEdit.EndDate = task.EndDate;
            taskToEdit.BeginDate = task.BeginDate;
            taskToEdit.Collaborator = collab;

            UnitOfWork.Save();
        }

        public void DeleteTask(string login, int idTask)
        {
            Collaborator collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            //verification de task
            if (!UnitOfWork.TaskRepository.Exists(t => t.ID == idTask))
            {
                throw new Exception("La tâche " + idTask + " n'existe pas");
            }
            Task task = UnitOfWork.TaskRepository.Single(t => t.ID == idTask);

            // si le collab loggué n'est pas le même que le collab de la tache alors il est RA ou CP (et les 2 sont associés)
            if (!(task.Collaborator.Login != login &&
                (collab.Job.ID == (int)JobEnum.ChefProjet && Utils.CollabAssociateToCP(collab, task.Collaborator)) ||
                (collab.Job.ID == (int)JobEnum.RA && Utils.CollabAssociateToRA(collab, task.Collaborator))
            ))
            {
                throw new Exception("Vous n'avez pas les droits necessaires.");
            }

            UnitOfWork.TaskRepository.Remove(task);
            UnitOfWork.Save();
        }

        public TaskViewModel GetTask(string login, int idTask)
        {
            Collaborator collab = UnitOfWork.CollaboratorRepository.Single(c => c.Login == login);

            //verification de task
            if (!UnitOfWork.TaskRepository.Exists(t => t.ID == idTask))
            {
                throw new Exception("La tâche " + idTask + " n'existe pas");
            }
            Task task = UnitOfWork.TaskRepository.Single(t => t.ID == idTask);

            // si le collab loggué n'est pas le même que le collab de la tache alors il est RA ou CP (et les 2 sont associés)
            if (!(task.Collaborator.Login != login &&
                (collab.Job.ID == (int)JobEnum.ChefProjet && Utils.CollabAssociateToCP(collab, task.Collaborator)) ||
                (collab.Job.ID == (int)JobEnum.RA && Utils.CollabAssociateToRA(collab, task.Collaborator))
            ))
            {
                throw new Exception("Vous n'avez pas les droits necessaires.");
            }

            TaskViewModel taskView = new TaskViewModel();
            taskView.ReferenceProject = task.Project.Reference;
            taskView.TypeOfTask = task.TaskType.ID;
            taskView.TJM = task.TJM.Value;
            taskView.EndDate = task.EndDate;
            taskView.BeginDate = task.BeginDate;
            taskView.LoginCollab = task.Collaborator.Login;

            return taskView;

        }
    }
}
